// src/utils/mqttClient.js
import mqtt from '@/plugins/mqtt.min.js'
import config from '@/config'

class MQTTClient {
	constructor() {
		this.client = null
		this.connected = false
		this.connecting = false
		this.clientId = config.mqtt.ClientIdPrefix + (config.mqtt.ClientId || Date.now().toString(36) + Math
			.random().toString(36).substr(2, 6))
		this.serverClientId = '';

		// 订阅管理
		this.subscriptions = new Map()

		// 请求处理器管理
		this.openApiCallbacks = new Map() // 存储所有请求的回调函数

		// 定时器
		this.reconnectTimer = null
		this.heartbeatTimer = null

		// 事件监听器
		this.eventListeners = {
			'connected': new Set(),
			'disconnected': new Set(),
			'message': new Set(),
			'error': new Set()
		}

		// 连接计数器
		this.connectionAttempts = 0;
	}

	/* 核心方法 */
	init() {
		if (this.client || this.connecting) return
		this.connecting = true
		this.connectionAttempts++;
		console.log(`[MQTT] 连接尝试 #${this.connectionAttempts} clientId:`, this.clientId)

		const protocol = this._getProtocol()
		const brokerUrl = `${protocol}://${config.mqtt.Server}:${config.mqtt.Port}${config.mqtt.Path}`

		const options = {
			clientId: this.clientId,
			username: config.mqtt.UserName,
			password: config.mqtt.Password,
			keepalive: config.mqtt.HeartbeatInterval || 60,
			clean: true,
			reconnectPeriod: 0,
			connectTimeout: 10000
		}

		try {
			console.log('[MQTT] 正在连接:', brokerUrl)
			this.client = mqtt.connect(brokerUrl, options)
			this._bindEvents()
			this.GlobalSubscriptions();
		} catch (err) {
			console.error('[MQTT] 连接异常:', err)
			this._handleError(err)
			this._scheduleReconnect()
		}
	}

	disconnect() {
		if (!this.client) return

		console.log('[MQTT] 正在断开连接...')
		this._clearTimers()

		try {
			this.client.end(true)
		} catch (err) {
			console.warn('[MQTT] 断开连接时异常:', err)
		} finally {
			this._cleanup()
			this._emit('disconnected')
		}
	}

	GlobalSubscriptions() {
		console.log("[MQTT] 注册全局订阅")
		// 订阅客户端ID响应主题
		this.subscribe(`${config.mqtt.DefaultPublishTopic}/${this.clientId}`, (msg) => {
			// console.log("[MQTT] 收到消息:", msg)
			if (!msg?.payload) {
				console.warn("[MQTT] 无效消息格式")
				return
			}

			const payload = msg.payload;
			// 修改：添加调试日志
			// console.log('[MQTT] 收到消息类型:', payload.respFunc);

			if (payload.respFunc === "RespClientid") {
				this.serverClientId = payload.data;
				console.log("[MQTT] 获取到 serverClientId:", this.serverClientId)
				this._emit('serverReady'); // 确保触发serverReady事件
			} else if (payload.respFunc === "RespError") {
				console.error("[MQTT] 错误响应:", payload)
				const errorData = this.deepLowerFirstKeys(payload.Data?.body || {});
				this._handleApiError(errorData);
			} else if (payload.respFunc === "RespOpenApi") {
				// console.log("[MQTT] API响应:", payload)
				// 修复：正确处理响应数据格式
				let response;
				try {
					response = typeof payload.data === 'string' ?
						JSON.parse(payload.data) :
						payload.data;
				} catch (e) {
					console.error("[MQTT] 解析响应失败:", e);
					response = payload.data;
				}

				// 确保id存在
				if (payload.id) {
					response = response || {};
					response.id = payload.id;
				}
				// console.log("[MQTT] 处理后的API响应:", response)
				this._handleApiResponse(response);
			} else {
				console.warn(`[MQTT] 未知响应类型: ${payload.respFunc}`);
			}
		})
	}

	// 修改：清理超时定时器
	_handleApiResponse(response) {
		if (!response || !response.id) {
			console.error("[MQTT] 无效API响应格式:", response)
			return
		}

		const requestId = response.id;
		if (this.openApiCallbacks.has(requestId)) {
			const {
				resolve,
				reject,
				timeout
			} = this.openApiCallbacks.get(requestId);
			clearTimeout(timeout); // 清除超时定时器

			try {
				const code = response.code || 200;
				if (code === 200) {
					// 修复：返回完整的响应对象
					resolve(response);
				} else {
					const msg = response.message || `请求失败，错误码: ${code}`;
					reject(new Error(msg));
				}
			} catch (error) {
				reject(error);
			} finally {
				this.openApiCallbacks.delete(requestId);
			}
		} else {
			console.warn(`[MQTT] 未找到匹配的回调 ID: ${requestId}`);
		}
	}


	_handleApiError(errorData) {
		const code = errorData.code || 500;
		const message = errorData.message || '未知错误';

		if (code === 401) {
			this._emit('unauthorized', message);
		} else {
			this._emit('apiError', {
				code,
				message
			});
		}
	}

	deepLowerFirstKeys(obj) {
		if (typeof obj !== 'object' || obj === null) return obj;
		if (Array.isArray(obj)) return obj.map(item => this.deepLowerFirstKeys(item));

		const newObj = {};
		for (const key in obj) {
			if (obj.hasOwnProperty(key)) {
				const newKey = key.charAt(0).toLowerCase() + key.slice(1);
				newObj[newKey] = this.deepLowerFirstKeys(obj[key]);
			}
		}
		return newObj;
	}

	/* 订阅/发布 */
	subscribe(topic, callback, qos) {
		if (!topic || typeof callback !== 'function') return
		const finalQos = qos ?? config.mqtt.DefaultQoS ?? 1
		const fullTopic = `${config.mqtt.TopicPrefix}/${topic}`

		if (!this.subscriptions.has(topic)) {
			this.subscriptions.set(topic, {
				callbacks: new Set([callback]),
				qos: finalQos
			})
		} else {
			this.subscriptions.get(topic).callbacks.add(callback)
		}

		if (this.connected) {
			this._doSubscribe(topic, fullTopic, finalQos)
		}
	}

	unsubscribe(topic, callback) {
		if (!this.subscriptions.has(topic)) return

		const subscription = this.subscriptions.get(topic)

		if (callback) {
			subscription.callbacks.delete(callback)
			if (subscription.callbacks.size === 0) {
				this._doUnsubscribe(topic)
			}
		} else {
			this._doUnsubscribe(topic)
		}
	}

	// HTTP方法封装
	get(url, data, headers) {
		return this._sendRequest({
			url: `${config.baseUrl}${url}`,
			method: "GET",
			data,
			headers
		});
	}

	post(url, data, headers) {
		return this._sendRequest({
			url: `${config.baseUrl}${url}`,
			method: "POST",
			data,
			headers
		});
	}

	put(url, data, headers) {
		return this._sendRequest({
			url: `${config.baseUrl}${url}`,
			method: "PUT",
			data,
			headers
		});
	}

	delete(url, data, headers) {
		return this._sendRequest({
			url: `${config.baseUrl}${url}`,
			method: "DELETE",
			data,
			headers
		});
	}

	_sendRequest(requestConfig) {
		return new Promise((resolve, reject) => {
			// 修复：添加连接状态检查
			if (!this.connected) {
				return reject(new Error('MQTT未连接'));
			}

			// 修复：添加serverClientId检查
			if (!this.serverClientId) {
				console.warn('[MQTT] 等待服务器客户端ID...');
				const readyHandler = () => {
					this.off('serverReady', readyHandler);
					this._doSendRequest(requestConfig, resolve, reject);
				};
				this.on('serverReady', readyHandler);
				return;
			}

			this._doSendRequest(requestConfig, resolve, reject);
		});
	}
	// 新增：实际发送请求的方法
	_doSendRequest(requestConfig, resolve, reject) {
		if (!this.serverClientId) {
			return reject(new Error('未获取到服务器客户端ID'));
		}

		const requestId = this._generateRequestId();

		// 存储回调
		this.openApiCallbacks.set(requestId, {
			resolve,
			reject,
			timeout: setTimeout(() => {
				if (this.openApiCallbacks.has(requestId)) {
					this.openApiCallbacks.delete(requestId);
					reject(new Error('请求超时'));
				}
			}, config.mqtt.RequestTimeout || 15000)
		});

		// 发布请求
		this.publishOpenApi(requestId, {
			...requestConfig
		});
	}
	publishOpenApi(requestId, data) {
		if (!this.serverClientId) {
			console.error("[MQTT] 发布失败: 未获取到服务器客户端ID");
			return false;
		}

		const payload = {
			clientId: this.clientId,
			data: data,
			id: requestId,
			func: "openapi",
			respFunc: "RespOpenApi"
		};
		return this.publish(`${config.mqtt.DefaultPublishTopic}/${this.serverClientId}`, payload);
	}

	publishClientId() {
		console.log("[MQTT] 发布客户端ID请求");
		this._publishDefault("clientid", "RespClientid", "publish ClientId");
	}

	_publishDefault(func, respFunc, data) {
		const payload = {
			clientId: this.clientId,
			data: data,
			func: func,
			respFunc: respFunc
		};

		this.publish(config.mqtt.DefaultSubscribeTopics, payload);
	}

	publish(topic, payload, qos = config.mqtt.DefaultQoS ?? 1) {
		if (!this.connected) {
			console.warn('[MQTT] 发布失败：未连接')
			return false
		}

		const fullTopic = `${config.mqtt.TopicPrefix}/${topic}`
		const payloadStr = typeof payload === 'string' ? payload : JSON.stringify(payload)

		if (payloadStr.length > ((config.mqtt.MaxPayloadSize * 1000) ?? 268435455)) {
			console.error('[MQTT] 消息超过大小限制')
			return false
		}

		return new Promise((resolve) => {
			this.client.publish(fullTopic, payloadStr, {
				qos
			}, (err) => {
				if (err) {
					console.error('[MQTT] 发布失败:', err)
					this._emit('error', {
						type: 'publish',
						topic,
						error: err
					})
					resolve(false)
				} else {
					console.log(`[MQTT] 发布成功: ${fullTopic}`)
					resolve(true)
				}
			})
		})
	}

	/* 事件管理 */
	on(event, callback) {
		if (this.eventListeners[event]) {
			this.eventListeners[event].add(callback)
		}
	}

	off(event, callback) {
		if (this.eventListeners[event]) {
			this.eventListeners[event].delete(callback)
		}
	}

	/* 私有方法 */
	_generateRequestId() {
		return Date.now().toString(36) + Math.random().toString(36).substr(2, 6);
	}

	_bindEvents() {
		this.client.on('connect', () => {
			console.log('[MQTT] 连接成功')
			this.connected = true
			this.connecting = false
			this.connectionAttempts = 0;
			this._clearTimers()
			this._startHeartbeat()
			this._resubscribe()
			this._emit('connected')

			// 连接成功后获取服务器客户端ID
			this.publishClientId();
		})

		this.client.on('error', (err) => {
			this._handleError(err)
		})

		this.client.on('close', () => {
			this._handleClose()
		})

		this.client.on('message', (topic, message) => {
			this._handleMessage(topic, message)
		})
	}

	_doSubscribe(topic, fullTopic, qos) {
		this.client.subscribe(fullTopic, {
			qos
		}, (err) => {
			if (err) {
				console.error(`[MQTT] 订阅失败 [${fullTopic}]:`, err)
				this._emit('error', {
					type: 'subscribe',
					topic,
					error: err
				})
			} else {
				console.log(`[MQTT] 订阅成功: ${fullTopic}`)
			}
		})
	}

	_doUnsubscribe(topic) {
		const fullTopic = `${config.mqtt.TopicPrefix}/${topic}`
		if (this.connected) {
			this.client.unsubscribe(fullTopic, (err) => {
				if (err) {
					console.error(`[MQTT] 取消订阅失败 [${fullTopic}]:`, err)
				} else {
					console.log(`[MQTT] 取消订阅成功: ${fullTopic}`)
				}
			})
		}
		this.subscriptions.delete(topic)
	}

	_handleMessage(topic, message) {
		try {
			let payload
			if (message instanceof ArrayBuffer) {
				payload = new TextDecoder('utf-8').decode(new Uint8Array(message))
			} else {
				payload = message.toString()
			}

			try {
				payload = JSON.parse(payload)
			} catch (e) {
				// 非JSON数据保持原样
			}

			const fullPrefix = `${config.mqtt.TopicPrefix}/`
			const shortTopic = topic.startsWith(fullPrefix) ?
				topic.substring(fullPrefix.length) :
				topic

			const messageData = {
				fullTopic: topic,
				shortTopic,
				payload
			}

			if (this.subscriptions.has(shortTopic)) {
				const {
					callbacks
				} = this.subscriptions.get(shortTopic)
				callbacks.forEach(cb => cb(messageData))
			}

			this._emit('message', messageData)

		} catch (err) {
			console.error('[MQTT] 消息处理异常:', err)
			this._emit('error', {
				type: 'message',
				error: err
			})
		}
	}

	_handleError(err) {
		console.error('[MQTT] 连接错误:', err)
		this._cleanup()
		this._emit('error', {
			type: 'connection',
			error: err
		})
		this._scheduleReconnect()
	}

	_handleClose() {
		console.log('[MQTT] 连接已关闭')
		this._cleanup()
		this._emit('disconnected')
		this._scheduleReconnect()
	}

	_scheduleReconnect() {
		this._clearTimers()

		const delay = Math.min(10000 * (this.connectionAttempts || 1), 60000);
		console.log(`[MQTT] ${delay/1000}秒后尝试重连`)

		this.reconnectTimer = setTimeout(() => {
			this.init()
		}, delay)
	}

	_resubscribe() {
		if (this.subscriptions.size === 0) return

		console.log('[MQTT] 恢复订阅...')
		this.subscriptions.forEach((sub, topic) => {
			const fullTopic = `${config.mqtt.TopicPrefix}/${topic}`
			this._doSubscribe(topic, fullTopic, sub.qos)
		})
	}

	_startHeartbeat() {
		this._stopHeartbeat()

		const interval = (config.mqtt.HeartbeatInterval || 60) * 1000
		this.heartbeatTimer = setInterval(() => {
			if (this.connected) {
				this.publish(
					config.mqtt.DefaultPublishTopic || 'heartbeat', {
						type: 'heartbeat',
						clientId: this.clientId,
						timestamp: Date.now()
					},
					0
				).catch(console.error)
			}
		}, interval)
	}

	_stopHeartbeat() {
		if (this.heartbeatTimer) {
			clearInterval(this.heartbeatTimer)
			this.heartbeatTimer = null
		}
	}

	_cleanup() {
		this.connected = false
		this.connecting = false

		if (this.client) {
			this.client.removeAllListeners()
			this.client = null
		}

		this._clearTimers()
		this.openApiCallbacks.clear();
	}

	_clearTimers() {
		this._stopHeartbeat()

		if (this.reconnectTimer) {
			clearTimeout(this.reconnectTimer)
			this.reconnectTimer = null
		}
	}

	_emit(event, data) {
		if (this.eventListeners[event]) {
			this.eventListeners[event].forEach(cb => cb(data))
		}
	}

	_getProtocol() {
		// #ifdef MP-WEIXIN
		return 'wxs'
		// #endif
		// #ifdef APP-PLUS
		return 'tcp'
		// #endif
		return 'ws'
	}
}

// 导出单例
const mqttInstance = new MQTTClient()
export default mqttInstance